using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Runtime.CompilerServices;
using mshtml;
using Dimok;
using Dimok.IE;
using Config = Dimok.Config;
namespace Credit.Objects{
	/// <summary>
	/// Pull credit from Equifax using IE and return it as innerText
	/// </summary>
	public class Equifax : MarshalByRefObject{
		public static MainForm Form;
		//protected static Dimok.IE.IE ie = (Application.OpenForms[0] as ICreditForm).ieh.ie;
		private static Dimok.IE.IE ie { get { return Form.IEH.ie; } }
		protected string rootUrl = Dimok.Config.Credit.equifax.RootURL;
		protected string preProfileUrl;
		protected string profileUrl = "";
		protected string mainFormUrl = "";
		private TextWriterTraceListener textListener;
		public Equifax(){
			preProfileUrl = rootUrl + Dimok.Config.Credit.equifax.AuthPath;
			//ie = (Application.OpenForms[0] as ICreditForm).ieh.ie;
			//ie.Init();
		}
		//NAME="accessReportsForm" 
		#region    ***** GetCredit *****
		public string GetCredit(string SSN,string firstName, string lastName,string city,string state){
			return GetCredit(SSN,firstName,lastName,city,state,"","","","");
		}
		public string GetCredit(string SSN,string firstName, string lastName,string city,string state,string zip){
			return GetCredit(SSN,firstName,lastName,city,state,zip,"","","");
		}
		public string GetCredit(string SSN,string firstName, string lastName,string city,string state,string SSN1,string firstName1,string lastName1){
			return GetCredit(SSN,firstName,lastName,city,state,"",SSN1,firstName1,lastName1);
		}
		[MethodImplAttribute(MethodImplOptions.Synchronized)]
		public string GetCredit(string SSN,string firstName, string lastName,string city,string state,string zip,string SSN1,string firstName1,string lastName1){

			for( int i=2; i > 0; i-- ){
				try{
					if( SubmitRequest(SSN,firstName,lastName,city,state,zip,SSN1,firstName1,lastName1) ) break;
				}catch(Dimok.IE.HTMLElementNotFoundException){
					throw;
				}catch(Exception){
					ie.Init();
				}
				if (!SelectProfile()) throw new ApplicationException("Can't find a profile after Login.");
			}
			string text = ie.doc.body.innerText;
			if( Regex.IsMatch(text,"(?:Report Inquiry Error|CERR Message)",RegexOptions.IgnoreCase|RegexOptions.Compiled) )
				throw new CreditInquiryException("<BASE href='"+Regex.Match(ie.doc.url,"^.+/").Value+"'>"+ie.doc.body.innerHTML);
			ie.GoBack();
			return text;
		}
		#endregion ***** GetCredit *****
		
		private bool SubmitRequest(string SSN,string firstName, string lastName,string city,string state,string zip,string SSN1,string firstName1,string lastName1){

			HTMLInputTextElement txtElement = GetFirstElementInNewReport();
			if( txtElement == null )return false;
			HTMLFormElement form = txtElement.form as HTMLFormElement;
			txtElement.value = lastName.ToUpper();
			GetTextElement(form,"SUBJECT_FIRST_NAME").value = firstName.ToUpper();
			GetTextElement(form,"SUBJECT_SSN").value = SSN;
			GetTextElement(form,"CUR_CITY").value = city.ToUpper();
			GetSelectElement(form,"CUR_STATE").value = state.ToUpper();

			GetTextElement(form,"SPOUSE_LAST_NAME").value = lastName1.ToUpper();
			GetTextElement(form,"SPOUSE_FIRST_NAME").value = firstName1.ToUpper();
			GetTextElement(form,"SPOUSE_SSN").value = SSN1;
			var goButton = (((IHTMLElementCollection)IE.Tags((IHTMLElement)form, "INPUT")).item("CONTINUE", 1) as HTMLInputButtonElement);
			if (goButton == null)
				goButton = (((IHTMLElementCollection)IE.Tags((IHTMLElement)form, "INPUT")).item("CONTINUE", 0) as HTMLInputButtonElement);
			if (goButton == null) throw new Dimok.IE.HTMLElementNotFoundException("[CONTINUE] button not found in New Report form.");
			//GetButtonElement(form,"CONTINUE").click();
			goButton.click();
			ie.WaitIE();
			return true;
		}
		HTMLInputTextElement GetFirstElementInNewReport() {
			HTMLDocument doc = ie.doc;
			mainFormUrl = doc.url;
			HTMLFormElement form = GetFormElement(doc, "theForm");
			if (form == null) return null;
			return GetTextElement(form, "SUBJECT_LAST_NAME");
		}
		#region    ***** Select Profile *****
		private bool NavigateToSelectProfile() {
			return NavigateToSelectProfile(preProfileUrl);
		}
		private bool NavigateToSelectProfile(string url) {
			ie.Navigate(url,true);
			if (NeedToLogin) Login();
			if (NavigateToSelectProfile(ie.doc.links)) return true;
			int i = 0;
			try {
				while (Dimok.IE.IE.Frame(ie.doc, i) != null)
					if (NavigateToSelectProfile(Dimok.IE.IE.Frame(ie.doc, i++).document.links)) return true;
			} catch (InvalidCastException) {
				return NavigateToSelectProfile(Dimok.Config.Credit.equifax.RootURL+Dimok.Config.Credit.equifax.EntryPath);
			}
			return false;
		}
		private bool NavigateToSelectProfile(IHTMLElementCollection links ){
			//IHTMLElementCollection links = ie.Frame(3).document.links;
			foreach( HTMLAnchorElement link in links )
				if (link.innerText != null && link.innerText.IndexOf("eCredit Information") >= 0) {
					link.click();
					ie.WaitIE();
					if (GetFirstElementInNewReport() == null) {
						HTMLAnchorElement newReport = ie.GetElementByText("A", "New Report") as HTMLAnchorElement;
						if (newReport == null) throw new Exception("No 'New Report' link found.");
						newReport.click();
					}
					HTMLSelectElement selRepProf = null;
					for (int i = 50; i > 0; i--) {
						selRepProf = ie.doc.getElementById("REPORT_PROFILE_ID") as HTMLSelectElement;
						if (selRepProf == null) IE.DoEventsAndWait(100); else break;
					}
					if (selRepProf == null) throw new Exception("REPORT_PROFILE_ID not found.");
					selRepProf.value = Config.Credit.equifax.ProfileValue;
					ie.WaitIE();
					profileUrl = ie.doc.url;
					return true;
				}

			return false;
			//throw new ApplicationException("No eCredit Information link on page " + ie.doc.url);
		}
		private bool SelectProfile(){
			return NavigateToSelectProfile();
			//ie.Navigate("https://www.eport.equifax.com/edat/authhome.jsp");
			HTMLFormElement form = GetFormElement(ie.doc,"accessReportsForm");
			if( form == null )return false;
			GetSelectElement(form,"REPORT_PROFILE_ID").value = Config.Credit.equifax.ProfileValue;
			GetButtonElement(form,"NEW_REPORTS").click();
			ie.WaitIE();
			return true;
		}
		#endregion ***** Select Profile *****
		
		private void Login(){
			ie.WaitIE();
			if (!NeedToLogin) return;
			HTMLFormElement form = GetFormElement(ie.doc,"theForm");
			//if( form == null )throw new ApplicationException("Unknown page: "+ie.doc.url);
			HTMLInputTextElement txtUserID = GetTextElement(form,"userID");
			if( txtUserID == null )throw new ApplicationException("No userID field on login page: "+ie.doc.url);
			txtUserID.value = Dimok.Config.Credit.equifax.UserName;
			HTMLInputTextElement txtCIT = GetTextElement(form,"CIT");
			if( txtCIT != null )txtCIT.value = Config.Credit.equifax.CompanyID;
			GetTextElement(form,"password").value = Dimok.Config.Credit.equifax.Password;
			HTMLInputButtonElement btnSubmit = GetButtonElement(form, "LOGIN");
			if (btnSubmit == null) btnSubmit = GetButtonElement(form, "SUBMIT");
			if (btnSubmit == null) btnSubmit = GetButtonElement(form, "action");
			if( btnSubmit == null )throw new ApplicationException("No submit button on login page: "+ie.doc.url);
			btnSubmit.click();
			ie.WaitIE(10000);
			if( (form=GetFormElement(ie.doc,"theForm")) != null && (txtUserID=GetTextElement(form,"challengeAnswser")) != null ){
				txtUserID.value = Config.Credit.equifax.Challenge;
				form.submit();
				ie.WaitIE();
			}
		}
		bool NeedToLogin { get { return GetFormElement(ie.doc, "theForm") != null && GetTextElement(GetFormElement(ie.doc, "theForm"), "userID") != null; } }

		#region    ***** Private *****
		private HTMLFormElement GetFormElement(HTMLDocument doc,string formName){
			try{
				return (HTMLFormElement)doc.forms.item(formName,null);
			}catch(Exception ex){ throw new Exception("Form:"+formName+Environment.NewLine,ex);}
		}
		private HTMLInputButtonElement GetButtonElement(HTMLFormElement form,string elementName){
			try{
				return (HTMLInputButtonElement)form.item(elementName,null);
			}catch(Exception ex){ throw new Exception("Element:"+elementName+Environment.NewLine,ex);}
		}
		private HTMLInputTextElement GetTextElement(HTMLFormElement form,string elementName){
			try{
				return (HTMLInputTextElement)form.item(elementName,null);
			}catch(Exception ex){ throw new Exception("Element:"+elementName+Environment.NewLine,ex);}
		}
		private HTMLSelectElement GetSelectElement(HTMLFormElement form,string elementName){
			try{
				return (HTMLSelectElement)form.item(elementName,null);
			}catch(Exception ex){ throw new Exception("Element:"+elementName+Environment.NewLine,ex);}
		}
		#endregion ***** Private *****
	}
}
